<script lang="ts" setup>
import type { PropType } from 'vue';
import { computed, defineEmits, defineProps } from 'vue';
import type { FormItemRule } from 'naive-ui';
import { NCheckbox, NDatePicker, NInput, NInputNumber, NRadioGroup, NSelect, NSwitch, NTimePicker } from 'naive-ui';
import type { FormElementType } from '../props';

// 表单元素类型

// 选项类型
interface Option {
  label: string;
  value: any;
  disabled?: boolean;
}

// 表单值类型映射
type FormValueType<T extends FormElementType> = T extends 'checkbox' | 'switch'
  ? boolean
  : T extends 'select' | 'radio'
    ? any
    : T extends 'date' | 'time'
      ? Date | null
      : T extends 'number'
        ? number
        : string;

const props = defineProps({
  // 表单字段路径
  path: {
    type: String,
    required: true
  },
  // 标签文本
  label: {
    type: String,
    default: ''
  },
  // 表单元素类型
  type: {
    type: String as PropType<FormElementType>,
    default: 'input',
    validator: (value: string) =>
      ['input', 'select', 'checkbox', 'radio', 'date', 'time', 'number', 'textarea', 'switch'].includes(value)
  },
  // 表单元素选项（用于select、radio等）
  options: {
    type: Array as PropType<Option[]>,
    default: () => []
  },
  // 表单验证规则
  rules: {
    type: Array as PropType<FormItemRule[]>,
    default: () => []
  },
  // 是否显示反馈
  showFeedback: {
    type: Boolean,
    default: true
  },
  // 反馈信息
  feedback: {
    type: String,
    default: ''
  },
  // 反馈类型
  feedbackType: {
    type: String as PropType<'info' | 'success' | 'warning' | 'error'>,
    default: 'info'
  },
  // 额外信息
  extra: {
    type: String,
    default: ''
  },
  // 表单值
  modelValue: {
    type: null,
    required: true
  },
  // 传递给表单元素的其他属性
  attrs: {
    type: Object as PropType<
      {
        // 例如：为默认值提供类型约束
        defaultValue?: FormValueType<FormElementType>;
        // 其他属性...
      } & Record<string, any>
    >,
    default: () => ({})
  }
});

const emit = defineEmits<{
  (e: 'update:modelValue', value: FormValueType<FormElementType>): void;
}>();

// 处理值更新
const handleUpdate = (value: FormValueType<typeof props.type>) => {
  emit('update:modelValue', value);
};

// 根据type计算要渲染的组件
const componentType = computed(() => {
  const componentMap = {
    input: NInput,
    select: NSelect,
    checkbox: NCheckbox,
    radio: NRadioGroup,
    date: NDatePicker,
    time: NTimePicker,
    number: NInputNumber,
    textarea: NInput.Textarea,
    switch: NSwitch
  };

  return componentMap[props.type] || NInput;
});

// 计算监听器 - 只提取真正的事件
const listeners = computed(() => {
  const eventMap = {
    input: 'input',
    select: 'update:value',
    checkbox: 'update:modelValue',
    radio: 'update:modelValue',
    date: 'update:value',
    time: 'update:value',
    number: 'update:value',
    textarea: 'input',
    switch: 'update:modelValue'
  };

  const eventName = eventMap[props.type] || 'input';

  // 从attrs中提取真正的事件监听器 (以on开头且第二个字符为大写)
  const extractedListeners = Object.entries(props.attrs).reduce(
    (acc, [key, value]) => {
      if (/^on[A-Z]/.test(key)) {
        acc[key] = value;
      }
      return acc;
    },
    {} as Record<string, any>
  );

  // 添加我们自己的事件处理器
  return {
    ...extractedListeners,
    [eventName]: handleUpdate
  };
});

// 计算属性 - 只包含非事件属性
const elementProps = computed(() => {
  // 过滤掉所有事件监听器
  return Object.entries(props.attrs).reduce(
    (acc, [key, value]) => {
      if (!/^on[A-Z]/.test(key)) {
        acc[key] = value;
      }
      return acc;
    },
    {} as Record<string, any>
  );
});
</script>

<template>
  <NFormItem
    :path="path"
    :label="label"
    :rule="rules"
    :show-feedback="showFeedback"
    :feedback="feedback"
    :feedback-type="feedbackType"
    :extra="extra"
  >
    <!-- 分别绑定属性和事件 -->
    <component :is="componentType" v-bind="elementProps" :value="modelValue" v-on="listeners" />
  </NFormItem>
</template>
